using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using Microsoft.Win32;
using System.IO;
using Wrath.Xml;
using Wrath.Windows.Forms;
using Wrath.RuleForge.RuleSets;
using Wrath.RuleForge.Property;
using Wrath.RuleForge.Imaging;
using ICSharpCode.SharpZipLib.Zip;
using Wrath.RuleForge.Windowing;

namespace Wrath.RuleForge
{
    public partial class MainForm : Form
    {
        #region DockPanels

        private OutputForm outputForm;
        private PropertyForm<Element> elementPropertyForm;
        private ImageViewer imageViewer;
        private RuleSetExplorer ruleSetExplorer;

        private IDockContent GetContentFromPersistString(string persistString)
        {
            if (persistString == typeof(RuleSetExplorer).ToString())
                return ruleSetExplorer;
            else if (persistString == typeof(PropertyForm<Element>).ToString())
                return elementPropertyForm;
            else if (persistString == typeof(OutputForm).ToString())
                return outputForm;

            return null;
        }

        #endregion

        public MainForm()
        {
            InitializeComponent();

            dockPanel.ShowDocumentIcon = true;
            dockPanel.Extender.AutoHideStripStyle = DockPanelExtender.AutoHideStyle.VS2005;

            EventBroker.RuleSetElementSelected += new EventBroker.ElementPropertyWrapperEventHandler(EventBroker_RuleSetElementSelected);
            EventBroker.FrameSelected += new EventBroker.PathEventHandler(EventBroker_FrameSelected);
            EventBroker.IconSelected += new EventBroker.PathEventHandler(EventBroker_IconSelected);
            EventBroker.FrameDoubleClicked += new EventBroker.ElementEventHandler(EventBroker_FrameDoubleClicked);
            EventBroker.WindowClassDoubleClicked += new EventBroker.ElementEventHandler(EventBroker_WindowClassDoubleClicked);
            EventBroker.CustomDieDoubleClicked += new EventBroker.ElementEventHandler(EventBroker_CustomDieDoubleClicked);
        }

        void EventBroker_WindowClassDoubleClicked(EventBroker.ElementEventArgs eventArgs)
        {
            WindowClassEditor editor = new WindowClassEditor(eventArgs.ElementData);
            editor.Show(dockPanel, DockState.Document);
        }

        void EventBroker_CustomDieDoubleClicked(EventBroker.ElementEventArgs eventArgs)
        {
            CustomDieEditor editor = new CustomDieEditor(eventArgs.ElementData);
            editor.Show(dockPanel, DockState.Document);
        }

        void EventBroker_FrameDoubleClicked(EventBroker.ElementEventArgs eventArgs)
        {
            FrameEditor editor = new FrameEditor(eventArgs.ElementData);
            editor.Show(dockPanel, DockState.Document);
        }

        void EventBroker_IconSelected(EventBroker.PathEventArgs pathEventArgs)
        {
            if (imageViewer.IsHidden)
            {
                imageViewer.Show(dockPanel);
                imageViewer.DockState = DockState.Document;
            }

            imageViewer.SetPicture(pathEventArgs.Path);
        }

        void EventBroker_FrameSelected(EventBroker.PathEventArgs pathEventArgs)
        {
            if (imageViewer.IsHidden)
            {
                imageViewer.Show(dockPanel);
                imageViewer.DockState = DockState.Document;
            }

            imageViewer.SetPicture(pathEventArgs.Path);
        }

        void EventBroker_RuleSetElementSelected(EventBroker.ElementPropertyWrapperEventArgs eventArgs)
        {
            if (elementPropertyForm.IsHidden)
            {
                elementPropertyForm.Show(dockPanel);
                elementPropertyForm.DockState = DockState.DockRight;
            }

            elementPropertyForm.Wrapper = eventArgs.ElementWrapper;
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            outputForm = new OutputForm();
            ruleSetExplorer = new RuleSetExplorer();
            elementPropertyForm = new PropertyForm<Element>();
            outputForm = new OutputForm();

            imageViewer = new ImageViewer();
            imageViewer.HideOnClose = true;
            imageViewer.DockableAreas = DockAreas.Document;
            imageViewer.ShowHint = DockState.Document;

            // Load window positions.
            DeserializeDockContent deserializeDockContent = new DeserializeDockContent(GetContentFromPersistString);
            try
            {
                dockPanel.LoadFromXml("RuleForge.Window.config", deserializeDockContent);
            }
            catch { }
        }

        internal void AddRuleSet(string ruleSet)
        {
            Globals.RuleSets.AddRuleSet(ruleSet);

            ToolStripMenuItem ruleSetMenuItem = new ToolStripMenuItem(ruleSet);
            ruleSetMenuItem.Name = ruleSet;
            ruleSetMenuItem.Click += new EventHandler(ruleSetOpenMenuItem_Click);

            ruleSetsToolStripMenuItem.DropDownItems.Insert(ruleSetsToolStripMenuItem.DropDownItems.Count - 2, ruleSetMenuItem);
        }

        internal void RemoveRuleSet(string ruleSet)
        {
            ToolStripMenuItem ruleSetMenuItem = (ToolStripMenuItem)ruleSetsToolStripMenuItem.DropDownItems[ruleSet];
            if (ruleSetMenuItem != null)
            {
                ruleSetsToolStripMenuItem.DropDownItems.Remove(ruleSetMenuItem);
            }

            Globals.RuleSets.RemoveRuleSet(ruleSet);
        }

        internal bool AddModule(string moduleName)
        {
            Globals.ModuleInformation mi = new Globals.ModuleInformation();
            mi.Filename = moduleName;

            string modulePath = Globals.FantasyGroundsPaths.Modules + "\\" + moduleName;
            string moduleCachePath = Globals.RuleForgePaths.ModuleCache + "\\" + Path.GetFileNameWithoutExtension(moduleName);

            FastZip zip = new FastZip();
            zip.ExtractZip(modulePath, moduleCachePath, "");

            //Zip.ZipHelper.ExtractZipFile(modulePath, moduleCachePath);

            string dataFilename = "";
            if (File.Exists(moduleCachePath + "\\db.xml")) dataFilename = "db.xml";
            else if (File.Exists(moduleCachePath + "\\client.xml")) dataFilename = "client.xml";

            if (!File.Exists(moduleCachePath + "\\definition.xml") || String.IsNullOrEmpty(dataFilename))
            {
                EventBroker.MessageEventArgs args = new EventBroker.MessageEventArgs("ERROR: Cannot find one or more module files:\n ModuleName: " + moduleName + "\n ModuleCache: " + moduleCachePath + "\n definition.xml: " + File.Exists(moduleCachePath + "\\definition.xml").ToString() + "\n DataFileName: " + dataFilename);
                EventBroker.FireDebugMessage(args);
                return false;
            }

            FileParser definitionParser;
            try
            {
                definitionParser = new FileParser(moduleCachePath + "\\definition.xml");
            }
            catch (FileFormatException e)
            {
                string errorMessage = String.Format("ERROR: Cannot parse {0}\n ...on line {1}: {2}", moduleCachePath + "\\definition.xml", e.LineNumber, e.Line);
                EventBroker.MessageEventArgs args = new EventBroker.MessageEventArgs(errorMessage);
                EventBroker.FireDebugMessage(args);
                return false;
            }
            catch (Exception e)
            {
                EventBroker.MessageEventArgs args = new EventBroker.MessageEventArgs("ERROR: Cannot parse " + moduleCachePath + "\\definition.xml\nINFO: " + e.Message);
                EventBroker.FireDebugMessage(args);
                return false;
            }

            // Set Name
            Element nameElement = definitionParser.FindFirstElement("name");
            if (nameElement != null)
            {
                mi.Name = nameElement.Value;
            }

            // Set Author
            Element authorElement = definitionParser.FindFirstElement("author");
            if (authorElement != null)
            {
                mi.Author = authorElement.Value;
            }

            // Set RuleSet
            Element ruleSetElement = definitionParser.FindFirstElement("ruleset");
            string rulesetName = "Misc";
            if (ruleSetElement != null)
            {
                rulesetName = ruleSetElement.Value;
                mi.RuleSet = rulesetName;
            }

            FileParser dataParser;
            try
            {
                dataParser = new FileParser(moduleCachePath + "\\" + dataFilename);
            }
            catch (FileFormatException e)
            {
                string errorMessage = String.Format("ERROR: Cannot parse {0}\n ...on line {1}: {2}", moduleCachePath + "\\definition.xml", e.LineNumber, e.Line);
                EventBroker.MessageEventArgs args = new EventBroker.MessageEventArgs(errorMessage);
                EventBroker.FireDebugMessage(args);
                return false;
            }
            catch (Exception e)
            {
                EventBroker.MessageEventArgs args = new EventBroker.MessageEventArgs("ERROR: Cannot parse " + moduleCachePath + "\\definition.xml\nINFO: " + e.Message);
                EventBroker.FireDebugMessage(args);
                return false;
            }

            Element categoryNameElement = dataParser.FindFirstElement("categoryname");
            if (categoryNameElement != null)
            {
                mi.Category = categoryNameElement.Value;
            }

            // Set Thumbnail
            if (File.Exists(moduleCachePath + "\\thumbnail.png"))
            {
                Image thumbnail = Image.FromFile(moduleCachePath + "\\thumbnail.png");
                mi.Thumbnail = thumbnail;
            }

            // Save Module Information for later use.
            Globals.Modules.AddModule(mi);

            // Build MenuItems
            ToolStripMenuItem ruleSetMenuItem = (ToolStripMenuItem)modulesToolStripMenuItem.DropDownItems[rulesetName];
            if (ruleSetMenuItem == null)
            {
                ruleSetMenuItem = new ToolStripMenuItem(rulesetName);
                ruleSetMenuItem.Name = rulesetName;
                modulesToolStripMenuItem.DropDownItems.Insert(modulesToolStripMenuItem.DropDownItems.Count - 2, ruleSetMenuItem);
            }

            ToolStripMenuItem moduleMenuItem = new ToolStripMenuItem(moduleName);
            moduleMenuItem.Name = moduleName;
            moduleMenuItem.Image = mi.Thumbnail;
            moduleMenuItem.Click += new EventHandler(moduleOpenMenuItem_Click);

            ruleSetMenuItem.DropDownItems.Add(moduleMenuItem);

            return true;
        }

        internal void RemoveModule(Globals.ModuleInformation mi)
        {
            ToolStripMenuItem ruleSetMenuItem = (ToolStripMenuItem)modulesToolStripMenuItem.DropDownItems[mi.RuleSet];
            if (ruleSetMenuItem != null)
            {
                ToolStripMenuItem moduleMenuItem = (ToolStripMenuItem)ruleSetMenuItem.DropDownItems[mi.Filename];
                if (moduleMenuItem != null)
                {
                    ruleSetMenuItem.DropDownItems.Remove(moduleMenuItem);
                }

                if (ruleSetMenuItem.DropDownItems.Count < 1)
                {
                    modulesToolStripMenuItem.DropDownItems.Remove(ruleSetMenuItem);
                }
            }
        }

        private void ruleSetOpenMenuItem_Click(object sender, EventArgs e)
        {
            if (CheckRuleSetSaved())
            {
                ToolStripMenuItem menuItem = (ToolStripMenuItem)sender;

                Globals.FantasyGroundsPaths.CurrentRuleSet = Globals.FantasyGroundsPaths.RuleSets + "\\" + menuItem.Text;
                EventBroker.PathEventArgs pathEventArgs = new EventBroker.PathEventArgs(Globals.FantasyGroundsPaths.CurrentRuleSet);
                EventBroker.FireRuleSetOpen(pathEventArgs);

                ShowRuleSetExplorer();
            }
        }

        private void moduleOpenMenuItem_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem menuItem = (ToolStripMenuItem)sender;

            MessageBox.Show(menuItem.Text);
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void manageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            RuleSetManager ruleSetManger = new RuleSetManager();
            ruleSetManger.ShowDialog(this);
        }

        private void manageToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            ModuleManager modManager = new ModuleManager();
            modManager.ShowDialog(this);
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                dockPanel.SaveAsXml("RuleForge.Window.config");
            }
            catch { }
        }

        private void outputToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!outputForm.IsActivated)
            {
                outputForm.Show(dockPanel, DockState.DockBottom);
            }
        }

        private void ruleSetExplorerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ShowRuleSetExplorer();
        }

        private void ShowRuleSetExplorer()
        {
            if (!ruleSetExplorer.IsActivated)
            {
                ruleSetExplorer.Show(dockPanel, DockState.DockRight);
            }
        }

        private void propertyWindowToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!imageViewer.IsActivated)
            {
                imageViewer.Show(dockPanel, DockState.Document);
            }
        }

        private void closeRuleSetToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (CheckRuleSetSaved())
            {
                Globals.FantasyGroundsPaths.CurrentRuleSet = "";
                FileBroker.Files.Clear();

                EventBroker.FireRuleSetClose();
            }
        }

        private bool CheckRuleSetSaved()
        {
            if (!String.IsNullOrEmpty(Globals.FantasyGroundsPaths.CurrentRuleSet))
            {
                DialogResult result = MessageBox.Show("Save current RuleSet?", "Save RuleSet", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
                if (result == DialogResult.Cancel) return false;
                else if (result == DialogResult.Yes)
                {
                    SaveRuleSet();
                }
            }
            return true;
        }

        private static void SaveRuleSet()
        {
            foreach (KeyValuePair<string, FileParser> file in FileBroker.Files)
            {
                FileParser parser = file.Value;
                parser.Save();
            }
        }

        private void fileToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
        {
            if (!String.IsNullOrEmpty(Globals.FantasyGroundsPaths.CurrentRuleSet))
            {
                saveRuleSetToolStripMenuItem.Enabled = true;
                closeRuleSetToolStripMenuItem.Enabled = true;
            }
            else
            {
                saveRuleSetToolStripMenuItem.Enabled = false;
                closeRuleSetToolStripMenuItem.Enabled = false;
            }
        }

        private void saveRuleSetToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveRuleSet();
        }

    }
}